Apache DeltaSpike - the CDI toolbox

Antoine Sabot-Durand

  • Senior Software Engineer
  • CDI co-spec lead, Java EE 8 EG
  • Red Hat, Inc.
  • @antoine_sd
  • www.next-presso.com
  • github.com/antoinesd

Rafael Benevides

  • Senior Software Engineer
  • DeltaSpike P.M.C member
  • Red Hat, Inc.
  • @rafabene
  • github.com/rafabene

Agenda

  • CDI Portable Extensions
  • What is DeltaSpike ?
  • Core Module
  • Other DeltaSpike Modules
  • Question & Answers

CDI Portable Extensions

Portable extensions

OCP (Open Closed Principle) in CDI
OCP final

Extensions, what for?

To integrate 3rd party libraries, frameworks or legacy components
To change existing configuration or behavior
To extend CDI and Java EE
Thanks to them, Java EE can evolve between major releases

Extensions, how?

rubik
Implement javax.enterprise.inject.spi.Extension
Register the Extension
Observe SPI events at boot time related to the bean manager lifecycle

More concretely

Service provider of the service javax.enterprise.inject.spi.Extension declared in META-INF/services
Just put the fully qualified name of your extension class in this file
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.Extension;

public class CdiExtension implements Extension {

    void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) {
    }
    //...

    void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) {
    }
}

Example: Injecting a String from a Properties file

    @Inject @Property("key1")
    private String property1;

    @Inject @Property("key2")
    private String property2;
It can be achieved by @Produces but it could lead to: Unsatisfied dependencies for type String with qualifiers @Property…​
    @Produces
    @Property("key1")
    public String propriedade1Producer()
    {
        return propertiesFile.getProperty("key1");
    }

Solution: Create a CDI Portable Extension

powerful
One of the most powerful feature of the CDI specification
Not really popularized, partly due to:
  1. Their high level of abstraction
  2. The good knowledge on Basic CDI and SPI
  3. Lack of information (CDI is often reduced to a basic DI solution)

What is DeltaSpike ?

CDI & DeltaSpike

hook
CDI is a specification. It doesn’t provide business features
but it includes a powerful hook to add these business features
The "Poortable extensions" feature is this hook
Thanks to it, CDI can be easily enhanced with new high level features

Apache DeltaSpike is…​

toolbox
A collection of ready to use extensions to help you in your projects
A toolbox to help you develop new CDI portable extensions
A great way to learn how to develop your own extension by browsing the source code
The most obvious entry point to CDI eco-system

Where does it come from ?

TODO Move content to here

A bit of history

TODO Move content to here

Modules and dependencies

TODO Move content to here

Module Core

Core - Exception Handler

public class InventoryActions {
    @PersistenceContext private EntityManager em;
    @Inject private Event<ExceptionToCatchEvent> catchEvent; (1)

    public Integer queryForItem(Item item) {
        try {
          Query q = em.createQuery("SELECT i from Item i where i.id = :id");
          q.setParameter("id", item.getId());
          return q.getSingleResult();
        } catch (PersistenceException e) {
          catchEvent.fire(new ExceptionToCatchEvent(e)); (2)
        }
    }
}
1The Event of generic type ExceptionToCatchEvent is injected into your class for use later within a try/catch block.
2The event is fired with a new instance of ExceptionToCatchEvent constructed with the exception to be handled.

Core - Exception Handler

Exceptions are handled asynchronously.
@ExceptionHandler  (1)
public class MyHandlers {
    void printExceptions(@Handles ExceptionEvent<Throwable> evt) { (2)
        System.out.println("Something bad happened:" +
        evt.getException().getMessage());
        evt.handleAndContinue(); (3)
    }
}
1Exception handler methods are registered on beans annotated with @ExceptionHandler
2The @Handles annotation on the first parameter designates this method as an exception handler.
3This handler does not modify the invocation of subsequent handlers, as designated by invoking handleAndContinue().

Core - Type-safe ProjectStage

The current ProjectStage can be injected.
@Inject
private ProjectStage projectStage;

//...

boolean isDevProjectStage = ProjectStage.Development.equals(this.projectStage);
You can also use the ProjectStage at XHTML files.
<h:panelGroup layout="block"rendered="#{applicationConfig.projectStage == 'Development'}" >
    <!-- HTML Snippet is shown only in Development stage -->
</h:panelGroup>

Core - Type-safe ProjectStage

Besides custom ProjectStages it is possible to use the following pre-defined ProjectStages:
  1. UnitTest
  2. Development
  3. SystemTest
  4. IntegrationTest
  5. Staging
  6. Production
It can be set using DeltaSpike Configuration
-D org.apache.deltaspike.ProjectStage=Development

Core - DeltaSpike Configuration Mechanism

Configuration API
String userName = ConfigResolver.getPropertyValue("user.name");  (1)
String dbUserName = ConfigResolver.getPropertyAwarePropertyValue("db.username"); (2)
Integer dbPort = ConfigResolver
    .resolve("db.port")  (3)
    .as(Integer.class)
    .withProjectStage(true)
    .withDefault(3306)
    .getValue();
Date deadline = ConfigResolver.resolve("project.deadline") (4)
  .as(Date.class, new CustomDateConverter()).getValue());
Properties
user.name = "Rafael"  (1)
db.username.Production = "Antoine" (2)
db.username.Development = "Benevides" (2)
db.port = 1234 (3)
project.deadline = 2017-04-01 (4)

Core - DeltaSpike Configuration Mechanism

Injection of configured values into beans using @ConfigProperty
@ApplicationScoped
public class SomeRandomService
{
    @Inject
    @ConfigProperty(name = "endpoint.poll.interval")
    private Integer pollInterval;

    @Inject
    @ConfigProperty(name = "endpoint.poll.servername")
    private String pollUrl;

    ...
 }

Core - DeltaSpike Configuration Mechanism

How to provide these Properties to DeltaSpike?

By default there are implementations for the following configuration sources (listed in the lookup order):
  1. System properties
  2. Environment properties
  3. JNDI values - the base name is "java:comp/env/deltaspike/"
  4. Properties file values - default filename is "META-INF/apache-deltaspike.properties"
You can also specify your own config file or create a custom ConfigSource (example: read from XML, JSON, DB, etc)

Core - Injecting Resources

DeltaSpike has simple APIs for performing basic resource loading and property file reading.
@Inject
@InjectableResource("myfile.properties")
private InputStream is;

public String getVersion() throws IOException {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
      return br.readLine();
    }
}
The InjectableResourceProvider interface can be implemented to allow reading from alternate sources if needed (e.g. database LOBs, NoSQL storage areas).